//---------------------------------------------------------------------------

#include <windows.h>
#include <shlobj.h>
#include <shlwapi.h>
#include <Winsock2.h>
#include <winerror.h>
#include <my_protocol.h>
#include <Mstcpip.h>
#include "filelib.h"
#include "socklib.h"
#pragma hdrstop

//---------------------------------------------------------------------------

#pragma argsused


 const MAX_CONN = 255;          //  SO_RECVTIMEO and SO_SNDTIMEO
 const L_PORT = 22334;


 WSADATA wsaData;
 SOCKET srvsocket;//, *csocket, newsock;
 sockaddr_in laddr;

 ULONG conns = 0;

 CLogFile LogFile;

void WinVerToStr(char** WinVerTxt,OSVERSIONINFO* WinVer)
{
 if(WinVer->dwMajorVersion==4)
 {
	 if(WinVer->dwMinorVersion==0)
	 {
		 if(WinVer->dwPlatformId==VER_PLATFORM_WIN32_NT)
			WinVerTxt="Windows NT 4.0";
		 else
			WinVerTxt="Windows 95";
	 }
	 else
	 if(WinVer->dwMinorVersion==10)
		WinVerTxt="Windows 98";
	 else
	 if(WinVer->dwMinorVersion==90)
		WinVerTxt="Windows 98";
 }  else
 if(WinVer->dwMajorVersion==5)
 {
	 if(WinVer->dwMinorVersion==0)
		WinVerTxt="Windows 2000";
	 else
	 if(WinVer->dwMinorVersion==1)
		WinVerTxt="Windows XP";
	 else
	 if(WinVer->dwMinorVersion==2)
		WinVerTxt="Windows Server 2003 / 2003R2";
 }  else
 if(WinVer->dwMajorVersion==6)
 {
	 if(WinVer->dwMinorVersion==0)
		WinVerTxt="Windows Vista/Windows Server \"Longhorn\"";
	 else
	 if(WinVer->dwMinorVersion==1)
		(*WinVerTxt)="Windows 7";
 }
}



DWORD __stdcall ClientThread(void* SockPointer)
{
 SOCKET csocket=*((SOCKET*)SockPointer);
 delete SockPointer;
 BYTE *pckt=new BYTE[16384];

 SetSocketKeepAlive(csocket,5000,1000);

 while(1)
 {
   int res = recv(csocket, (BYTE*)pckt, 16384,NULL);
   if(res>0)
   {
	   if(GetPacketType(pckt,res)==PACKET_CMD)
	   {
		   CmdPacket cmd;
		   ParcePacket(pckt,res,&cmd);
		   if(cmd.command==CMD_BEEP) Beep(*((WORD*)cmd.data),*((WORD*)cmd.data+1));  else
		   if(cmd.command==CMD_SHUTDOWN)
		   {
				ExitWindowsEx(*((UINT*)cmd.data), SHTDN_REASON_MAJOR_APPLICATION|SHTDN_REASON_MINOR_OTHER);
		   }
		   delete [] cmd.data;
	   } else
	   if(GetPacketType(pckt,res)==PACKET_TELNET)
	   {
		   TelnetPacket cmd;
		   ParcePacket(pckt,res,&cmd);
		   delete [] cmd.str;
	   }

   } else if(res==0)
   {
	   LogFile.WriteLog("Connection is closed by client");
	   shutdown(csocket,SD_BOTH);
	   closesocket(csocket);
	   break;

   } else
   {
	   int err=WSAGetLastError();
	   if(err==WSAENETRESET||err==WSAECONNABORTED||err==WSAECONNRESET)
	   {
			LogFile.WriteLog("Connection lost");
			closesocket(csocket);
			break;
	   }
   }
   Sleep(20);
 }
}



DWORD __stdcall Thread(void* pParams)
{
 sockaddr_in caddr;
 int addrsize=sizeof(caddr);
 SOCKET *newsock=new SOCKET;
 SOCKET *passsock;
 while(1)
 {
   *newsock = accept(srvsocket, (sockaddr*)&caddr, &addrsize);
   if(*newsock==INVALID_SOCKET)   continue;
   char* ip=inet_ntoa(caddr.sin_addr);
   LogFile.WriteLog("Connected. IP: ",LOGFILE_NOENDOFLINE);
   LogFile.WriteLog(ip,LOGFILE_DONTADDTIME);

   passsock=new SOCKET;
   *passsock=*newsock;
   CloseHandle(CreateThread(0,0,ClientThread,passsock,0,0));
 }
}


WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
 char path[MAX_PATH];
 SHGetFolderPath(NULL,CSIDL_DESKTOPDIRECTORY,NULL,NULL,path);
 PathAppend(path,"server.log");
 LogFile.OpenLog(path);
 LogFile.ResetLog();

 char* WinVerTxt=NULL;
 OSVERSIONINFO WinVer;
 WinVer.dwOSVersionInfoSize=sizeof(OSVERSIONINFO);
 GetVersionEx(&WinVer);
 WinVerToStr(&WinVerTxt,&WinVer);

 LogFile.WriteLog("Server startup");
 LogFile.WriteLog("Windows version: ",LOGFILE_NOENDOFLINE);
 LogFile.WriteLog(WinVerTxt,LOGFILE_DONTADDTIME);
 if(WinVer.dwMajorVersion<5)
 {
	 LogFile.WriteLog("Unsupportable Windows version. Server can't work properly.");
	 LogFile.WriteLog("Server shutdown.");
	 return 1;
 }


 HANDLE hToken;
 TOKEN_PRIVILEGES tkp;

 OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken);
 LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME,&tkp.Privileges[0].Luid);
 tkp.PrivilegeCount = 1;  // one privilege to set
 tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
 AdjustTokenPrivileges(hToken, FALSE, &tkp, 0,(PTOKEN_PRIVILEGES)NULL, 0);



 WSAStartup(MAKEWORD(1,1),&wsaData);
 LogFile.WriteLog(wsaData.szDescription,LOGFILE_NOENDOFLINE);
 LogFile.WriteLog(": ",LOGFILE_NOENDOFLINE|LOGFILE_DONTADDTIME);
 LogFile.WriteLog(wsaData.szSystemStatus,LOGFILE_DONTADDTIME);

 srvsocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
 if(srvsocket==INVALID_SOCKET)
 {
	 LogFile.WriteLog("Creating server socket failed.");
	 LogFile.WriteLog("Server shutdown.");
	 return 1;
 }
 laddr.sin_family = AF_INET;
 laddr.sin_port=htons(L_PORT);
 laddr.sin_addr.s_addr = INADDR_ANY;
 bind(srvsocket,(const sockaddr*)&laddr, sizeof(laddr));
 listen(srvsocket, SOMAXCONN);

 CloseHandle(CreateThread(0,0,Thread,0,0,0));

 DWORD sent;
 while(1)
 {
   Sleep(50000);
 }
 WSACleanup();
 //delete [] buff;
	return 0;
}
//---------------------------------------------------------------------------

